package expression;

import vm.runtime.NextVMRuntime;

import java.util.*;
import java.util.logging.XMLFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class BoolExpression {
    public static boolean getBool(String expression, NextVMRuntime nextVMRuntime) throws Exception {

        /**
         * 1 == 1                       True
         * 1 == 2                       False
         * 1 >= 2                       False
         * True                         True
         * False                        False
         * 1 != 1                       True
         * 1 <= 10                      True
         * a() < 10                     True
         * b(10 , True , 1 < 2) == 10   False
         *
         * a()                          True
         */
        // Remove all spaces from the expression
        expression = expression.trim();
        if (expression.equalsIgnoreCase("true")) {
            return true;
        }
        else if (expression.equalsIgnoreCase("false")) {
            return false;
        }
        else {
            //String regex = "(.*?)(\\s*==\\s*|\\s*!=\\s*|\\s*>=\\s*|\\s*<=\\s*|\\s*<\\s*|\\s*>)\\s*(.*)";
            //Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
            //Matcher matcher = pattern.matcher(expression);
            String[] Tokens = splitBoolExpressionTokens(expression);
            //System.out.println(Arrays.toString(Tokens)+"            "+expression);
            if (Tokens.length == 3) {
                String part1 = Tokens[0].trim();
                String part2 = Tokens[1].trim();
                String part3 = Tokens[2].trim();

                Object x = BaseExpression.Deal(new String[]{part1} , nextVMRuntime)[0];
                Object y = BaseExpression.Deal(new String[]{part3} , nextVMRuntime)[0];
                //System.out.println(x.getClass().getSimpleName()+" "+y.getClass().getSimpleName());
                //System.out.println(evaluateOperation(x , y , part2,nextVMRuntime)+" "+x+" "+y);
                return evaluateOperation(x , y , part2,nextVMRuntime);
            }
            else{
                //System.out.println(expression);
                Object[] objects = BaseExpression.Deal(new String[]{expression} , nextVMRuntime);
                //System.out.println(Arrays.toString(objects));
                if (objects[0] != null) {
                    return Boolean.parseBoolean(String.valueOf(objects[0]));
                }
                throw new Exception("Bool Error: "+expression);
            }
        }
    }
    public static boolean canConvertToString(Object obj) {
        // 检查对象是否为null
        if (obj == null) {
            return false;
        }

        // 检查对象是否是String, Number, 或 Character的实例
        return obj instanceof String || obj instanceof Number || obj instanceof Character;
    }

    public static String[] splitBoolExpressionTokens(String exp) {
        /**
         * "hello world"
         * "hello \"world"
         * "hello" , "world"
         * a("hello world" , "hello world" , b("a")),
         * "hello" , 100.0 , 200
         */
        boolean isIn_1 = false; // ( or )
        boolean isIn_2 = false; // "
        boolean isIn_3 = false; // , and ,
        int In_1_format_number = 0;
        ArrayList<String> TokenArrays = new ArrayList<>();

        StringBuffer tmp_str = new StringBuffer();
        String[] s_str = exp.split("");
        for (int i = 0; i < s_str.length ;i++) {
            /**
             * 先统计逗号进行分割
             */
            String s = s_str[i];
            if (s.equals("\"") && isIn_1) {
                tmp_str.append(s);
                continue;
            }
            else if (s.equals("\"") && !isIn_2) {
                isIn_2 = true;
                tmp_str.append(s);
                continue;
            }
            else if (s.equals("\"") && isIn_2) {
                isIn_2 = false;
                tmp_str.append(s);
                TokenArrays.add(tmp_str.toString());
                tmp_str = new StringBuffer();
                continue;
            }
            else if (s.equals("\\") && isIn_2) {
                i += 1;
                tmp_str.append(s);
                tmp_str.append(s_str[i]);
                continue;
            }
            else if ((s.equals("=") || s.equals("!")) && !isIn_1 && !isIn_2) {
                /**
                 * ==
                 * !=
                 */
                if (i + 1 != s_str.length) {
                    String next_str = s_str[i+1];
                    if (next_str.equals("=")) {
                        TokenArrays.add(tmp_str.toString());
                        tmp_str = new StringBuffer();
                        tmp_str.append(s);
                        tmp_str.append(next_str);
                        i += 1;
                        TokenArrays.add(tmp_str.toString());
                        tmp_str = new StringBuffer();
                        continue;
                    }
                }
                if (tmp_str.toString().trim().isEmpty()) {
                    continue;
                }

                TokenArrays.add(tmp_str.toString());
                tmp_str = new StringBuffer();
                tmp_str.append(s);
                TokenArrays.add(tmp_str.toString());
                tmp_str = new StringBuffer();
                continue;
            }
            else if ((s.equals(">") || s.equals("<")) && !isIn_1 && !isIn_2) {
                /**
                 * >=
                 * <=
                 * >
                 * <
                 */
                if (i + 1 != s_str.length) {
                    String next_str = s_str[i+1];
                    if (next_str.equals("=")) {
                        tmp_str.append(s);
                        tmp_str.append(next_str);
                        i += 1;
                        TokenArrays.add(tmp_str.toString());
                        tmp_str = new StringBuffer();
                        continue;
                    }
                }
                if (tmp_str.toString().trim().isEmpty()) {
                    continue;
                }
                TokenArrays.add(tmp_str.toString());
                tmp_str = new StringBuffer();
                tmp_str.append(s);
                TokenArrays.add(tmp_str.toString());
                tmp_str = new StringBuffer();
                continue;
            }
            else if (s.equals("(") && !isIn_2) {
                isIn_1 = true;
                In_1_format_number += 1;
                tmp_str.append(s);
                continue;
            }
            else if (s.equals(")") && isIn_1 && !isIn_2) {
                In_1_format_number -= 1;
                tmp_str.append(s);
                if (In_1_format_number == 0) {
                    TokenArrays.add(tmp_str.toString());
                    tmp_str = new StringBuffer();
                    isIn_1 = false;
                }
                continue;
            }
            else  {
                tmp_str.append(s);
                //System.out.println(i+1 + " "+s_str.length);
                if (i + 1 == s_str.length) {
                    TokenArrays.add(tmp_str.toString());
                }
            }
        }
        TokenArrays.removeIf(Objects::isNull);
        TokenArrays.removeIf(" "::equals);
        //System.out.println("===============================");
        //System.out.println(TokenArrays);
        //System.out.println(exp);
        //System.out.println("===============================");
        //System.out.println();
        return TokenArrays.toArray(new String[0]);
    }
    private static boolean evaluateOperation(Object left, Object right, String operator, NextVMRuntime nextVMRuntime) throws Exception {
        boolean result = true;
        switch (operator) {
            case "==" :
                if (left instanceof Boolean && right instanceof Boolean) {
                    return left == right;
                }else {
                    if (StringExpression.IsNumber(String.valueOf(left)) && StringExpression.IsNumber(String.valueOf(right)))
                    {
                        double a = Double.parseDouble(String.valueOf(left));
                        double b = Double.parseDouble(String.valueOf(right));
                        //System.out.println(a == b);
                        return a == b;
                    }
                    else if (canConvertToString(left) && canConvertToString(right)) {
                        String x = String.valueOf(left).trim();
                        String y = String.valueOf(right).trim();
                        //System.out.println(x+" "+y);
                        return x.equals(y);
                    }
                    else {
                        return left.equals(right);
                    }
                }
            case "<=" :
                double x = Double.parseDouble(String.valueOf(left));
                double y = Double.parseDouble(String.valueOf(right));
                result = x <= y;
                break;
            case ">=" :
                double x_1 = Double.parseDouble(String.valueOf(left));
                double y_1 = Double.parseDouble(String.valueOf(right));
                result = x_1 >= y_1;
                break;
            case "!=" :
                if (left instanceof Boolean && right instanceof Boolean) {
                    result = left != right;
                }else {
                    if (StringExpression.IsNumber(String.valueOf(left)) && StringExpression.IsNumber(String.valueOf(right)))
                    {
                        double a = Double.parseDouble(String.valueOf(left));
                        double b = Double.parseDouble(String.valueOf(right));
                        result = a != b;
                        break;
                    }
                    else if (canConvertToString(left) && canConvertToString(right)) {
                        String xA = String.valueOf(left).trim();
                        String yA = String.valueOf(right).trim();
                        result = !xA.equals(yA);
                        break;
                    }
                    else {
                        result = !left.equals(right);
                        break;
                    }
                }
                break;
            case "<" :
                double x_2 = Double.parseDouble(String.valueOf(left));
                double y_2 = Double.parseDouble(String.valueOf(right));
                result = x_2 < y_2;
                break;
            case ">" :
                double x_3 = Double.parseDouble(String.valueOf(left));
                double y_3 = Double.parseDouble(String.valueOf(right));
                result = x_3 > y_3;
                break;
            default:
                result = false;
                break;
        }

        return result;
    }
}
